package cgl.narada.service.security.kmc.messages;

import java.io.IOException;
import java.io.Serializable;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.Certificate;

import org.apache.log4j.Logger;

import cgl.narada.service.ServiceException;
import cgl.narada.service.security.impl.EntityOperationsImpl;
import cgl.narada.util.ObjectMarshaller;

public class SignedRequest implements Serializable {
    static Logger log = Logger.getLogger("SignedRequest");
    
    private byte[] request;
    private Certificate ownerCertificate;
    private byte[] signedDigest;

    // Disable this Constructor
    private SignedRequest() {
    }

    public SignedRequest(byte[] req, Certificate cert) {
       request = new byte[req.length];
       
       System.arraycopy(req, 0, request, 0, req.length);       
       ownerCertificate = cert;
       signedDigest = null;
    }

    public boolean generateSignedDigest(PrivateKey privKey) {
       try {
          EntityOperationsImpl entityOperations = new EntityOperationsImpl();
          signedDigest = entityOperations.signPayload(request,
                   privKey);
       } catch (ServiceException e) {
          log.error("Exception when generating Signature: ", e);
          log.info("Process Abandoned");
          return false;
       }

       return true;
    }

    public boolean verify() {
        return verify(ownerCertificate.getPublicKey());
    }

    public boolean verify(PublicKey pubKey) {
        try {
           EntityOperationsImpl entityOperations = new EntityOperationsImpl();
           return entityOperations.validateSignature(signedDigest, request, pubKey);

        } catch (ServiceException e) {
           log.error("", e);
           return false;
        }
     }
    
    /**
     * Marshalls the object into an array of bytes.
     * 
     * @return an array of bytes representing the marshaller object, null if
     *         error occurs
     */
    public byte[] getBytes() {

       if (signedDigest == null) {
           log.error("MUST sign using private key");
           return null;
       }
           
       try {
          return ObjectMarshaller.marshall(this);
       } catch (IOException e) {
          log.error("", e);
          return null;
       }
    }

    /**
     * Unmarshalls the bytes as a SignedRequest object
     * 
     * @param objectBytes
     * @return SignedRequest if successful, null if error occurs
     */
    public static SignedRequest createObjectFromBytes(
             byte[] objectBytes) {
       try {
          return (SignedRequest) ObjectMarshaller
                   .unmarshall(objectBytes);
       } catch (IOException e) {
          log.error("", e);
       } catch (ClassNotFoundException e) {
          log.error("", e);
       }
       return null;
    }

    /**
     * @return Returns the request.
     */
    public byte[] getRequest() {
        return request;
    }    
}
